Skip to content

Conversation

@rajeshvelicheti
Copy link

Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests pass
  • Appropriate READMEs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕

fjuma and others added 30 commits May 15, 2025 09:31
Add TaskStore and TaskManager
Implement the ability to send a streaming message request using A2AClient#sendStreamingMessage
Add the event classes from the Python implementation
kabir and others added 12 commits June 20, 2025 10:49
Share the Executor used for async operations
Refactor A2A.getAgentCard() to use AgentCardProducer.

Python impl uses different exception types from what we were.
…erver, and update dependencies accordingly (#124)

This PR splits the examples into two different modules, one for client
and one for server and updates the instructions accordingly. It also
cleans up some dependencies and removes unnecessary ones.
…a2a-java-sdk-server-common module (#129)

This PR splits out server related code from the `a2a-java-sdk-core`
module into a new `a2a-java-sdk-server-common` module that is used by
the quarkus and jakarta server modules.

This reduces the dependencies required by the `a2a-java-sdk-core`
module.
I found some unused imports in the project. This PR removes them to keep
the code clean.

Signed-off-by: Sun Yuhan <[email protected]>
Co-authored-by: Sun Yuhan <[email protected]>
This PR includes the following changes:  

1. Added a unit test class for the `RequestContext` class, and all unit
tests have been verified to pass. This is based on the unit test class
from the `a2a` Python sdk:
`tests/server/agent_execution/test_context.py`, with a few tests that
are not applicable to the Java version removed.

2. Based on the unit test class, an issue in the `RequestContext` class
was identified and fixed: the `relatedTasks` setting in the constructor
was not working properly.

Fixes #60

---------

Signed-off-by: Sun Yuhan <[email protected]>
Co-authored-by: Sun Yuhan <[email protected]>
# Description

for issue task #20


- [x] Follow the [`CONTRIBUTING` Guide](../CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests pass
- [ ] Appropriate READMEs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @rajeshvelicheti, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request marks the initial release of the Java SDK for the Agent2Agent (A2A) Protocol. It establishes a comprehensive framework for building A2A-compliant applications in Java, encompassing both client and server functionalities. The changes include a modular project structure, detailed protocol specification, robust HTTP communication utilities, and clear documentation with practical examples to facilitate adoption and contribution.

Highlights

  • Initial SDK Release: This pull request introduces the foundational Java SDK for the Agent2Agent (A2A) Protocol, establishing core client and server components.
  • Comprehensive Protocol Implementation: The SDK includes detailed Java representations of A2A protocol elements such as Agent Cards, Messages, Tasks, Artifacts, and various data parts (text, file, data), along with robust JSON-RPC message handling.
  • Full-Featured A2A Client: A complete A2A client is provided, supporting synchronous and streaming message sending, task management (retrieval, cancellation), and push notification configuration, leveraging a new HTTP client abstraction.
  • Flexible A2A Server Implementations: The SDK offers common server-side components for agent execution and task management, with specific implementations for Jakarta REST and Quarkus Reactive Routes, enabling diverse deployment options.
  • Extensive Documentation and Examples: New README.md, CONTRIBUTING.md, LICENSE, and SECURITY.md files are added, alongside 'Hello World' client and server examples, to guide users and contributors.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several new files and modifies existing ones to implement the A2A (Agent2Agent) protocol in Java. It includes core functionalities, server implementations for Jakarta REST and Quarkus Reactive Routes, client functionalities, and example usages. The changes also cover documentation, licensing, security reporting, and contributing guidelines.

@maeste maeste mentioned this pull request Jun 27, 2025
4 tasks

@Override
public EventQueue tap(String taskId) {
synchronized (taskId) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential issue with string interning.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed in #146. Originally by syncing on this.queues, later by replacing with ConcurrentHashMap


@ApplicationScoped
public class InMemoryQueueManager implements QueueManager {
private final Map<String, EventQueue> queues = Collections.synchronizedMap(new HashMap<>());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be ConcurrentHashMap?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146

public EventQueue tap(String taskId) {
synchronized (taskId) {
EventQueue queue = queues.get(taskId);
if (queue == null) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: return null over return queue for better readability primarily because there is a null comparision before return. Also, if queues is a ConcurrentHashMap, it might be
EventQueue queue = queues.get(taskId);
return queue != null ? queue.tap() : null;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146

private final PushNotifier pushNotifier;
private final Supplier<RequestContext.Builder> requestContextBuilder;

private final Map<String, CompletableFuture<Void>> runningAgents = Collections.synchronizedMap(new HashMap<>());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConcurrentHashMap maybe since there is a lot of async handling.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146

.build(),
queue);

CompletableFuture<Void> cf = runningAgents.get(task.getId());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use async composition.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally clear what you mean here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of something like this

runningAgents.getOrDefault(task.getId(), CompletableFuture.completedFuture(null)).cancel(true); but this is more of a nit for readability, might not have a large gain.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or even

Optional.ofNullable(runningAgents.get(task.getId()))
.ifPresent(task -> task.cancel(true));


abstract void signalQueuePollerStarted();

public void enqueueEvent(Event event) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async via CompetableFuture may be?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not totally clear again :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as dequeue, public CompletableFuture enqueueEvent(Event event) {..}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rajeshvelicheti Just wondering whether or not it makes sense to make enqueueEvent async and return a CompletableFuture. With this approach, it doesn't seem like we can guarantee the order in which events get added to the queue.

For example, if enqueueEvent(eventA) is called followed by enqueueEvent(eventB) and if the enqueueEvent method is async and uses something like this code snippet to handle adding the event, it doesn't seem like we can guarantee that eventA will be added to the queue before eventB:

return CompletableFuture.supplyAsync(() -> {
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Unable to acquire the semaphore to enqueue the event", e);
            }
            queue.add(event);
            // Call toString() since for errors we don't really want the full stacktrace
            log.debug("Enqueued event {} {}", event instanceof Throwable ? event.toString() : event, this);
            return null;
        });

@rajeshvelicheti Please let us know if we are missing something or if you had something else in mind. Thanks!


abstract EventQueue tap();

public Event dequeueEvent(int waitMilliSeconds) throws EventQueueClosedException {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async via CompletableFuture may be?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not clear to me

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Kabir. I thought, public CompletableFuture dequeueEvent(int waitMilliSeconds) throws EventQueueClosedException {...}

might help in this, given how the method is structured is being used.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class EventQueue {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the usage, AutoCloseable might help the consumers.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146

@ApplicationScoped
public class InMemoryTaskStore implements TaskStore {

private final Map<String, Task> tasks = Collections.synchronizedMap(new HashMap<>());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConcurrentHashMap maybe?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146


private final EventQueue parent;
// TODO decide on a capacity (or more appropriate queue data structures)
private final BlockingQueue<Event> queue = new ArrayBlockingQueue<Event>(1000);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be unbounded to handle blocking better, a bounded semaphore to handle back pressure might be effective

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit wooly on the details, but I have replaced ArrayBlockingQueue with LinkedBlockingQueue. The latter has a constructor where you don't specify the capacity, so I took a guess at this being a better structure from your input. Then I added a fair semaphore to deal with the capacity.

Those changes are in #146.

If I have misunderstood something, please let me know.

@kabir
Copy link
Collaborator

kabir commented Jul 1, 2025

@rajeshvelicheti I believe I have addressed most of your comments in #146.

I wasn't sure what you meant where you mentioned CompletableFuture, so I have left those for now

.build(),
queue);

CompletableFuture<Void> cf = runningAgents.get(task.getId());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of something like this

runningAgents.getOrDefault(task.getId(), CompletableFuture.completedFuture(null)).cancel(true); but this is more of a nit for readability, might not have a large gain.

.build(),
queue);

CompletableFuture<Void> cf = runningAgents.get(task.getId());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or even

Optional.ofNullable(runningAgents.get(task.getId()))
.ifPresent(task -> task.cancel(true));

private void cleanupProducer(String taskId) {
// TODO the Python implementation waits for the producerRunnable
CompletableFuture<Void> cf = runningAgents.get(taskId);
if (cf != null) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if cf is null? would the queuemanager need to close?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, cf !=null could be avoided for readability

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cf means there is an active task being processed. In which case we remove (i.e. 'close') that task from the queuemanager. The queuemanager itself remains open.

That said, having revisited the code, I don't think the future can be null, so I will try removing the null check.


@Override
public Flow.Publisher<StreamingEventKind> onMessageSendStream(MessageSendParams params) throws JSONRPCError {
TaskManager taskManager = new TaskManager(
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

153-175 have same code, might be useful to convert to a common method. Nit

}

} finally {
if (interrupted) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both if and else do the same thing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a TODO with something to investigate from the Python implementation


// if the taskId and contextId were specified, they must match the params
if (params != null) {
if (taskId != null && ! params.message().getTaskId().equals(taskId)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: taskId.equals might be more helpful as there is a not null comparison on taskId already. Potential NPE

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

} else {
checkOrGenerateTaskId();
}
if (contextId != null && ! params.message().getContextId().equals(contextId)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Potential NPE.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

if (taskId != null && ! params.message().getTaskId().equals(taskId)) {
throw new InvalidParamsError("bad task id");
} else {
checkOrGenerateTaskId();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: heavy constructor

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave this as-is for now. We need to create an id if not specified

if (contextId != null && ! params.message().getContextId().equals(contextId)) {
throw new InvalidParamsError("bad context id");
} else {
checkOrGenerateContextId();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: heavy constructor

private List<String> getTextParts(List<Part<?>> parts) {
return parts.stream()
.filter(part -> part.getKind() == Part.Kind.TEXT)
.map(part -> (TextPart) part)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextPart - is this always expected? would the cast fail in any case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method seems too indicate we're explicitly looking for TextParts, and since we're filtering on Kind.TEXT the cast cannot fail

}

public List<Task> getRelatedTasks() {
return relatedTasks;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returning a modifiable collection, is this okay? looking at the references might help to return an un-modifiable collection

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've wrapped it in Collections.unmodifiableList() for now.

The main user seems to be the AgentExecutor, and I'm not totally clear if those should be able to add to this list. That said, there is a RequestContext.attachRelatedTask() that AgentExecutor implementors can call.

return;
} catch (Exception e) {
// Continue polling until there is a final event
continue;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the tube closed in this case as well?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I don't remember the exact details of if/how the Python implementation evolved in this area. But looking at the latest code there, it seems to do the equivalent of what you say.

I've updated this as per your suggestion.

return ZeroPublisher.create(conf, tube -> {
boolean completed = false;
try {
while (true) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential infinite loop, do we expect the tube to close all the time so there is no infinite loop?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should listen until the queue is closed (signalled via an EventQueueClosedException), an error is received, or a 'final' event is received.

I believe that is handled correctly?

kabir added a commit that referenced this pull request Jul 3, 2025
# Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make
sure it goes smoothly:

- [x] Follow the [`CONTRIBUTING` Guide](../CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests pass
- [x] Appropriate READMEs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕
*/
public A2ACardResolver(A2AHttpClient httpClient, String baseUrl, String agentCardPath, Map<String, String> authHeaders) {
this.httpClient = httpClient;
if (!baseUrl.endsWith("/")) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

java.net.URI over string, could help with the slashes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182

private final String url;
private final Map<String, String> authHeaders;

static String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent.json";
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be private final

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182


static String DEFAULT_AGENT_CARD_PATH = "/.well-known/agent.json";

static final TypeReference<AgentCard> AGENT_CARD_TYPE_REFERENCE = new TypeReference<>() {};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be private final

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182

}

private static boolean isStreamingRequest(String requestBody) {
return requestBody.contains(A2A.SEND_STREAMING_MESSAGE_METHOD) ||
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could be better handled by converting the body to a json object and inspect the appropriate element, method in this case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182

requestBody.contains(A2A.SEND_TASK_RESUBSCRIPTION_METHOD);
}

private static boolean isNonStreamingRequest(String requestBody) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could not find any references to this method.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182

// TODO There is the following line in the Python code I don't totally get
// asyncio.create_task(self._continue_consuming(event_stream))
// I think it means the continueConsuming() call should be done in another thread
continueConsuming(all);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be useful to get this executed in a background thread. CompletableFuture.runAsync might be more helpful in this case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #182. Please let us know if that's not what you had in mind.

@fjuma
Copy link
Collaborator

fjuma commented Jul 11, 2025

Hi @rajeshvelicheti, thanks for the feedback! I've addressed the latest comments in #182.

maeste pushed a commit that referenced this pull request Jul 11, 2025
# Description

This PR incorporates the latest feedback from
#138.

- [x] Follow the [`CONTRIBUTING` Guide](../CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests pass
- [x] Appropriate READMEs were updated (if necessary)
@fjuma
Copy link
Collaborator

fjuma commented Aug 6, 2025

@rajeshvelicheti Since we've addressed all the comments here, I'll go ahead and close this. Feel free to re-open.

@fjuma fjuma closed this Aug 6, 2025
kabir pushed a commit to kabir/a2a-java that referenced this pull request Dec 23, 2025
# Description

This PR incorporates the latest feedback from
a2aproject#138.

- [x] Follow the [`CONTRIBUTING` Guide](../CONTRIBUTING.md).
- [x] Make your Pull Request title in the
<https://www.conventionalcommits.org/> specification.
- Important Prefixes for
[release-please](https://github.com/googleapis/release-please):
- `fix:` which represents bug fixes, and correlates to a
[SemVer](https://semver.org/) patch.
- `feat:` represents a new feature, and correlates to a SemVer minor.
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking
change (indicated by the `!`) and will result in a SemVer major.
- [x] Ensure the tests pass
- [x] Appropriate READMEs were updated (if necessary)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants